package com.haiyou.sdk.account;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.redisson.client.protocol.ScoredEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.haiyou.common.constants.ErrCode;
import com.haiyou.common.constants.ErrorCode;
import com.haiyou.common.constants.game.GameConstants;
import com.haiyou.common.constants.sdk.AccountConstants;
import com.haiyou.common.constants.sdk.ChannelConstants;
import com.haiyou.common.event.asyc.AsyncEventBuses;
import com.haiyou.common.http.HttpResult;
import com.haiyou.common.http.HttpResultUtils;
import com.haiyou.common.jdbc.DbType;
import com.haiyou.common.system.Properties;
import com.haiyou.common.util.check.Assert;
import com.haiyou.common.util.string.StringUtil;
import com.haiyou.common.util.time.ServerTime;
import com.haiyou.common.util.uid.IdUtils;
import com.haiyou.data.game.role.PlayerRoleTable;
import com.haiyou.data.game.role.PlayerRoleTableAccessor;
import com.haiyou.data.game.role.PlayerTable;
import com.haiyou.data.game.role.PlayerTableAccessor;
import com.haiyou.data.sdk.account.SdkAccountTable;
import com.haiyou.data.sdk.account.SdkAccountTableAccessor;
import com.haiyou.data.sdk.account.UidAccountIdTable;
import com.haiyou.data.sdk.account.UidAccountIdTableAccessor;
import com.haiyou.data.sdk.account.token.AccountTokenService;
import com.haiyou.data.sdk.account.token.AdminToken;
import com.haiyou.data.sdk.event.RegisterEvent;
import com.haiyou.protocol.http.sdk.login.AuthRequest;
import com.haiyou.protocol.http.sdk.player.GetDataRequest;
import com.haiyou.protocol.http.sdk.player.GetDataResponse;
import com.haiyou.protocol.http.sdk.player.GetRankRequest;
import com.haiyou.protocol.http.sdk.player.PlayerInfoResponse;
import com.haiyou.protocol.http.sdk.player.UpdateDataRequest;
import com.haiyou.sdk.rank.RankScoreEntity;
import com.haiyou.sdk.rank.RankScoreRank;
import com.haiyou.sdk.thirdSdk.AiWanSdkService;
import com.haiyou.sdk.thirdSdk.HaiYoSdkService;
import com.haiyou.sdk.thirdSdk.WeChatSdkService;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 账号系统
 * 
 * @author xingyuan
 * @Date 2023年6月19日 上午11:45:53
 */
@Slf4j
@Component
public class AccountService {

	@Autowired
	private PlayerRoleTableAccessor roleTableAccessor;
	@Autowired
	private PlayerTableAccessor playerTableAccessor;

	@Autowired
	private AccountTokenService tokenService;

	@Autowired
	private SdkAccountTableAccessor accountTableAccessor;

	@Autowired
	private UidAccountIdTableAccessor uidAccountIdTableAccessor;

	@Autowired
	private HaiYoSdkService haiYoSdkService;

	@Autowired
	private AiWanSdkService aiWanSdkService;
	
	
	private static String EMPTY_STRING = "";
	
	private static String EFFECT_STRING = "1";
	
	/**
	 * 关闭自动定位
	 */
	private static String PROPERTY_KEY_CLOSE_AUTO_LOCATION = "closeAutoLocation";
	/**
	 * 自动定位
	 */
	private static String PROPERTY_KEY_AUTO_LOCATION = "autoLocation";
	/**
	 * 修改定位
	 */
	private static String PROPERTY_KEY_CHANGE_LOCATION = "changeLocation";
	/**
	 *  更新排行榜key
	 */
	private static String PROPERTY_KEY_UPDATE_RANK_KEY = "gainFrameHopeReward";
	/**
	 *  最近重置时间
	 */
	private static String PROPERTY_KEY_SERVER_RESET_TIME = "s_resetTime";

	private boolean validAdminLogin(String uid) {
		AdminToken token = tokenService.getAdminTokenById(uid);
		if (token != null && token.getExpireTime() > System.currentTimeMillis()) {
			return true;
		}
		return false;
	}


	/**
	 * 
	 * @param id       数据id
	 * @param username 用户名/账号/邮箱/手机号/sdkUid
	 * @param phone    手机号
	 * @param password 密码
	 * @param channel  渠道
	 * @return
	 */
	public SdkAccountTable register(String id, String username, String phone, String password, String channel) {

		Assert.isTrue(StringUtils.hasLength(id), ErrCode.ERROR_PARAMETER, "注册出现异常");
		Assert.isTrue(StringUtils.hasLength(channel), ErrCode.ERROR_PARAMETER, "注册出现异常");
		Assert.isTrue(StringUtils.hasLength(username), ErrCode.ERROR_PARAMETER, "注册出现异常");

		UidAccountIdTable uidAccountIdTable = new UidAccountIdTable();

		// 密码进行加密
		SdkAccountTable accountTable = accountTableAccessor.compute(id, (k, v) -> {

			if (!ObjectUtils.isEmpty(v)) {
				return v;
			}
			v = new SdkAccountTable();
			v.setId(k);
			v.setCreateTime(ServerTime.timeMillis());
			v.setPhone(phone);
			String uid = accountTableAccessor.uidNext();

			v.setUid(uid);
			v.setUsername(username);
			v.setChannel(channel);

			if (!StringUtils.hasLength(phone)) {
				v.setPhone(AccountConstants.not_bind_phone);
			}

			v.setEmail(AccountConstants.not_bind_mail);
			v.setPassword(password);

			uidAccountIdTable.setAccountId(k);
			uidAccountIdTable.setId(uid);

			return v;
		});

		// 创建数据
		uidAccountIdTableAccessor.compute(uidAccountIdTable.getId(), (k, v) -> {
			return uidAccountIdTable;
		});

		return accountTable;
	}


	/**
	 * 直接创建版本
	 * 
	 * @param request
	 * @return
	 */
	public HttpResult authTokenV1(AuthRequest request) {

		// 登录uid
		String uid = request.getUid();
		// token
		String token = request.getToken();
		// 渠道
		String channel = request.getChannel();
		
		log.info("uid={},token={},channel={}",uid,token,channel);

		channel = ChannelConstants.convert(channel);

		request.setChannel(channel);

		// 需要能处理的渠道
		Assert.isTrue(ChannelConstants.contain(channel), ErrorCode.ERROR_PARAMETER);

		Assert.isTrue(StringUtils.hasLength(channel), ErrorCode.ERROR_PARAMETER);

		Assert.isTrue(StringUtils.hasLength(token) || StringUtils.hasLength(uid), ErrorCode.ERROR_PARAMETER);

		String username = EMPTY_STRING;

		boolean adminLogin = false;

		// 存在特殊token
		if (StringUtils.hasLength(Properties.game_admin_login_token())) {

			if (Properties.game_admin_login_token().equals(token)) {
				adminLogin = true;
				username = request.getUid();
			}
		}

		// 超登
		if (!adminLogin) {
			switch (channel) {
			// 嗨哟登录
			case ChannelConstants.haiyou: {
				username = haiYoSdkService.authSign(request);
				break;
			}
			case ChannelConstants.wechat: {
				username = WeChatSdkService.authSign(request);
				break;
			}
			case ChannelConstants.aiwan: {
				username = aiWanSdkService.authSign(request);
				break;
			}
			case ChannelConstants.aiwan_cn: {
				username = aiWanSdkService.authSign(request);
				break;
			}

			case ChannelConstants.aiwan_xx: {
				username = aiWanSdkService.authSign(request);
				break;
			}
			default: {
				Assert.isTrue(false, ErrorCode.ERROR_PARAMETER);
			}
			}
		}

		String id = IdUtils.createId(username, request.getChannel());

		SdkAccountTable accountTable = accountTableAccessor.get(id);

		if (ObjectUtils.isEmpty(accountTable)) {
			accountTable = register(id, username, EMPTY_STRING, AccountConstants.not_set_password, request.getChannel());
		} else {
			// 判断是否正在超登中，超登中阻断正常登录
			if (validAdminLogin(accountTable.getUid())) {
				log.error("账号超登中,id:{}", id);
				return HttpResultUtils.failResult(ErrCode.ACCOUNT_LOCKED, "账号锁定中,请联系管理员");
			}
		}

		// 回包
		PlayerInfoResponse response = new PlayerInfoResponse();
		PlayerTable playerTable = loginQuery(accountTable.getUid(), 1, null);

		response.setUid(accountTable.getUid());
		response.setToken(String.valueOf(playerTable.getPlayerId()));
		response.setPlayerId(playerTable.getPlayerId());
//		response.setName(playerTable.getName());
//		response.setIcon(playerTable.getIcon());
		response.setCreateTime(playerTable.getCreateTime());
//		response.setData(playerTable.getData());

		return HttpResultUtils.successResult(response);
	}

	/**
	 * 登录查询
	 * 
	 * @param uid
	 * @param serverId
	 * @param ai       ai类型
	 * @return
	 */
	public PlayerTable loginQuery(String uid, int serverId, String name) {
		return queryPlayerTable(uid, serverId, name);
	}

	/**
	 * 查询玩家信息
	 * 
	 * @param uid
	 * @param serverId
	 * @return
	 */
	public PlayerTable queryPlayerTable(String uid, int serverId, String name) {

		PlayerRoleTable playerRoleTable = roleTableAccessor.getByUid(uid);

		if (playerRoleTable == null) {

			String key = roleTableAccessor.generateKey(uid);

			playerRoleTable = roleTableAccessor.compute(key, (k, v) -> {

				if (v == null) {
					v = new PlayerRoleTable();
					v.setId(k);
					v.setUid(uid);
				}
				return v;
			});
		}

		long playerId = playerRoleTable.getRoles().getOrDefault(serverId, -1l);

		PlayerTable playerTable = null;

		if (playerId <= 0) {
			// 注册用户角色信息
			playerTable = register(uid, serverId, name);
		} else {
			playerTable = playerTableAccessor.get(playerId);
		}

		return playerTable;
	}

	/**
	 * 注册玩家
	 * 
	 * @param playerId
	 * @param uid
	 */
	public PlayerTable register(String uid, int serverId, String name) {

		// 创建玩家数据
		long playerId = playerTableAccessor.playerIdNext();
		// 初始名称

		if (ObjectUtils.isEmpty(name)) {
			StringBuffer sbName = new StringBuffer();
			sbName.append(playerId);
			name = sbName.toString();
		}

		Date now = new Date();
		PlayerTable playerTable = playerTableAccessor.compute(playerId, (k, v) -> {

			if (v == null) {
				v = new PlayerTable();
				v.setId(k);
				v.setPlayerId(playerId);
				v.setUid(uid);
				v.setLoginTime(now);
				v.setServerId(serverId);
			}

			return v;
		});

		// 创建playerInfo

		String key = roleTableAccessor.generateKey(uid);

		roleTableAccessor.compute(key, (k, v) -> {
			v.getRoles().put(serverId, playerId);
			return v;
		});

		// 抛出注册事件
		AsyncEventBuses.getInstance().postEvent(RegisterEvent.build(uid, playerId, serverId));

		return playerTable;
	}

	/**
	 * 验证token
	 * 
	 * @param request
	 * @return
	 */


	// TODO 验证token

	/**
	 * 获得多键对应的value
	 * 
	 * @param request
	 * @return
	 */
	public HttpResult getData(GetDataRequest request) {
		if (ObjectUtils.isEmpty(request.getKeys())) {
			HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "没有参数");
		}

		long playerId = getPlayerIdByToken(request.getToken());

		List<String> keys = StringUtil.parseListByString(request.getKeys(), GameConstants.PARSE_COMMA);
		PlayerTable table = playerTableAccessor.get(playerId);
		if (table == null) {
			return HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "账号验证错误");
		}

		Map<String, String> result = Maps.newHashMap();
		HashMap<String, String> data = table.getData();
		for (String key : keys) {
			String value = data.getOrDefault(key, EMPTY_STRING);
			result.put(key, value);
		}

		GetDataResponse resp = new GetDataResponse();
		resp.setData(result);
		return HttpResultUtils.successResult(resp);
	}

	private long getPlayerIdByToken(String token) {
		return Long.parseLong(token);
	}

	/**
	 * 更新key值
	 * 
	 * @param request
	 * @return
	 */
	public HttpResult updateData(UpdateDataRequest request) {
		if (ObjectUtils.isEmpty(request.getKey())) {
			HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "没有参数k");
		}
		
		long playerId = getPlayerIdByToken(request.getToken());

		PlayerTable table = playerTableAccessor.compute(playerId, (k, v) -> {
			if (v == null) {
				return v;
			}
			v.getData().put(request.getKey(), request.getValue());
			return v;
		});

		if (table == null) {
			return HttpResultUtils.failResult(ErrCode.ERROR_PARAMETER, "账号验证错误");
		}

		Map<String, String> result = Maps.newHashMap();
		result.put(request.getKey(), table.getData().getOrDefault(request.getKey(), EMPTY_STRING));
		GetDataResponse resp = new GetDataResponse();
		resp.setData(result);
		
		// 如果是通关，更新排行榜
		if (request.getKey().equals(PROPERTY_KEY_UPDATE_RANK_KEY)) {
			updateRank(table, 1);
		}
		
		return HttpResultUtils.successResult(resp);
	}
	
	private int getLocation(PlayerTable table) {
		HashMap<String, String> data = table.getData();
		// 关闭定位
		if (EFFECT_STRING.equals(data.getOrDefault(PROPERTY_KEY_CLOSE_AUTO_LOCATION, EMPTY_STRING))) {
			return 0;
		}
		
		// 修改过定位
		String chagneLocation = data.get(PROPERTY_KEY_CHANGE_LOCATION);
		if (!ObjectUtils.isEmpty(chagneLocation)) {
			return Integer.parseInt(chagneLocation);
		}
		// 自动定位
		String autoLocation = data.get(PROPERTY_KEY_AUTO_LOCATION);
		if (!ObjectUtils.isEmpty(autoLocation)) {
			return Integer.parseInt(autoLocation);
		}
		return 0;
	}

	/**
	 * 更新排行榜排名
	 */
	private void updateRank(PlayerTable player, int addition) {
		// 所在区县榜单
		int areaId = getLocation(player);
		// 区县排行榜
		int cityId = areaId / 100 * 100;
		
		// 今日0点时间
		RankScoreRank rank = RankScoreRank.build(cityId, DbType.GAME_DB);
		// 更新排行榜
		rank.updateRank(new RankScoreEntity((long) areaId, addition));
		// 市排行榜
		int cId = areaId / 10000 * 10000;
		if (cId != cityId) {
			rank = RankScoreRank.build(cId, DbType.GAME_DB);
			// 更新排行榜
			rank.updateRank(new RankScoreEntity((long) cityId, addition));
		}

		// 省排行榜
		int proId = areaId / 1000000 * 1000000;
		if (proId != cId) {
			rank = RankScoreRank.build(proId, DbType.GAME_DB);
			// 更新排行榜
			rank.updateRank(new RankScoreEntity((long) cId, addition));
		}
	}
	
	/**
	 * 省市区县排行榜
	 * 
	 * @param request.getId()
	 * @return 
	 */
	public HttpResult getRank(GetRankRequest request) {
		RankScoreRank rank = RankScoreRank.build(request.getId(), DbType.GAME_DB);
		Collection<ScoredEntry<Long>> ranks = rank.getRankAllData(500);
		List<List<Long>> rankResult = Lists.newArrayList();
		for (ScoredEntry<Long> r : ranks) {
			rankResult.add(Lists.newArrayList(r.getValue(), r.getScore().longValue()));
		}
		return HttpResultUtils.successResult(rankResult);
	}
}
